using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Collections;
using System.Reflection;

using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swpublished;
using SolidWorks.Interop.swconst;
using SolidWorksTools;
using SolidWorksTools.File;


namespace SwConvertBack
{
    /// <summary>
    /// Summary description for SwConvertBack.
    /// </summary>
    [Guid("dbd23867-65e5-42fe-9cb4-7879898d0718"), ComVisible(true)]
    [SwAddin(
        Description = "SwConvertBack description",
        Title = "SwConvertBack",
        LoadAtStartup = true
        )]
   
    public class SwAddin : ISwAddin
    {
        public  struct SWVersionInfo
        {
            
            public string MajorSolidWorksVersion;
            public int VersionHistoryValue;
        }

        public List<SWVersionInfo> SWVList = new List<SWVersionInfo>();


        public SWVersionInfo CreateSWVersionInfo(string MajorSolidWorksVersion, int VersionHistoryValue)
        {
            SWVersionInfo temp = new SWVersionInfo();
            temp.MajorSolidWorksVersion = MajorSolidWorksVersion;
            temp.VersionHistoryValue = VersionHistoryValue;
            return temp;
        }
       

        #region Local Variables
        ISldWorks iSwApp;
        ICommandManager iCmdMgr;
        int addinID;
        public int VersionHistoryID;
        #region Event Handler Variables
        Hashtable openDocs;
        SolidWorks.Interop.sldworks.SldWorks SwEventPtr;
        #endregion
        
        #region Property Manager Variables
        UserPMPage ppage;
        #endregion
        //public System.Collections.Generic.List<Feature>  ListofFeatures
        //{
        //    get
        //    {
        //        return Properties.Settings.Default.ListofFeatures;
        //    }

        //    set
        //    {
        //         Properties.Settings.Default.ListofFeatures = value;
                      
        //    }
        //}
      

        // Public Properties
        public ISldWorks SwApp
        {
            get { return iSwApp; }
        }
        public ICommandManager CmdMgr
        {
            get { return iCmdMgr; }
        }

        public Hashtable OpenDocs
        {
            get { return openDocs; }
        }

        #endregion

        #region SolidWorks Registration
        [ComRegisterFunctionAttribute]
        public static void RegisterFunction(Type t)
        {

            #region Get Custom Attribute: SwAddinAttribute
            SwAddinAttribute SWattr = null;
            Type type = typeof(SwAddin);
            foreach (System.Attribute attr in type.GetCustomAttributes(false))
            {
                if (attr is SwAddinAttribute)
                {
                    SWattr = attr as SwAddinAttribute;
                    break;
                }
            }
            #endregion

            Microsoft.Win32.RegistryKey hklm = Microsoft.Win32.Registry.LocalMachine;
            Microsoft.Win32.RegistryKey hkcu = Microsoft.Win32.Registry.CurrentUser;

            string keyname = "SOFTWARE\\SolidWorks\\Addins\\{" + t.GUID.ToString() + "}";
            Microsoft.Win32.RegistryKey addinkey = hklm.CreateSubKey(keyname);
            addinkey.SetValue(null, 0);

            addinkey.SetValue("Description", SWattr.Description);
            addinkey.SetValue("Title", SWattr.Title);

            keyname = "Software\\SolidWorks\\AddInsStartup\\{" + t.GUID.ToString() + "}";
            addinkey = hkcu.CreateSubKey(keyname);
            addinkey.SetValue(null, Convert.ToInt32(SWattr.LoadAtStartup), Microsoft.Win32.RegistryValueKind.DWord);
        }

        [ComUnregisterFunctionAttribute]
        public static void UnregisterFunction(Type t)
        {
            Microsoft.Win32.RegistryKey hklm = Microsoft.Win32.Registry.LocalMachine;
            Microsoft.Win32.RegistryKey hkcu = Microsoft.Win32.Registry.CurrentUser;

            string keyname = "SOFTWARE\\SolidWorks\\Addins\\{" + t.GUID.ToString() + "}";
            hklm.DeleteSubKey(keyname);

            keyname = "Software\\SolidWorks\\AddInsStartup\\{" + t.GUID.ToString() + "}";
            hkcu.DeleteSubKey(keyname);
        }

        #endregion

        #region ISwAddin Implementation
        public SwAddin()
        {
           
        }
        private void createVersionlist()
        {
  
            SWVList.Add( CreateSWVersionInfo("SolidWorks 95", 44));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 96", 243));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 97 ", 483));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 97Plus", 629));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 98", 822));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 98Plus", 1008));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 99 ", 1137));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2000", 1500));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2001 ", 1750));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2001Plus", 1950));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2003 ", 2200));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2004 ", 2500));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2005", 2800));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2006", 3100));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2007", 3400));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2008", 3800));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2009", 4100));
            SWVList.Add(CreateSWVersionInfo("SolidWorks 2010", 4400));
        }
    
        [PreEmptive.Attributes.Setup(CustomEndpoint =".info/PreEmptive.Web.Services.Messaging/MessagingServiceV2.asmx")]
      
        public bool ConnectToSW(object ThisSW, int cookie)
        {
            createVersionlist();
      
            iSwApp = (ISldWorks)ThisSW;
            addinID = cookie;
           
    
            //Setup callbacks
            iSwApp.SetAddinCallbackInfo(0, this, addinID);

            #region Setup the Command Manager
            iCmdMgr = iSwApp.GetCommandManager(cookie);
            AddCommandMgr();
            #endregion

            #region Setup the Event Handlers
            SwEventPtr = (SolidWorks.Interop.sldworks.SldWorks)iSwApp;
            openDocs = new Hashtable();
            AttachEventHandlers();
            #endregion

         

            return true;
        }
        [PreEmptive.Attributes.Teardown()]
        public bool DisconnectFromSW()
        {
            RemoveCommandMgr();
          
            DetachEventHandlers();

            iSwApp = null;
            //The addin _must_ call GC.Collect() here in order to retrieve all managed code pointers 
            GC.Collect();
            return true;
        }
        #endregion

        #region UI Methods
        public void AddCommandMgr()
        {
            ICommandGroup cmdGroup;
            BitmapHandler iBmp = new BitmapHandler();
            Assembly thisAssembly;
            int cmdIndex0, cmdIndex1;
            string Title = "ConvertBack", ToolTip = "C# Addin";


            int[] docTypes = new int[]{(int)swDocumentTypes_e.swDocASSEMBLY,
                                       (int)swDocumentTypes_e.swDocDRAWING,
                                       (int)swDocumentTypes_e.swDocPART};

            thisAssembly = System.Reflection.Assembly.GetAssembly(this.GetType());

            cmdGroup = iCmdMgr.CreateCommandGroup(1, Title, ToolTip, "", -1);
            cmdGroup.LargeIconList = iBmp.CreateFileFromResourceBitmap("SwConvertBack.ToolbarLarge.bmp", thisAssembly);
            cmdGroup.SmallIconList = iBmp.CreateFileFromResourceBitmap("SwConvertBack.ToolbarSmall.bmp", thisAssembly);
            cmdGroup.LargeMainIcon = iBmp.CreateFileFromResourceBitmap("SwConvertBack.MainIconLarge.bmp", thisAssembly);
            cmdGroup.SmallMainIcon = iBmp.CreateFileFromResourceBitmap("SwConvertBack.MainIconSmall.bmp", thisAssembly);

            cmdIndex0 = cmdGroup.AddCommandItem("Export", -1, "Export", "Export", 0, "ExportPart", "", 0);
            cmdIndex1 = cmdGroup.AddCommandItem("Import", -1, "Import", "Import", 2, "ImportPart", "canImport", 2);

            cmdGroup.HasToolbar = true;
            cmdGroup.HasMenu = true;
            cmdGroup.Activate();

            bool bResult;

            foreach (int type in docTypes)
            {
                ICommandTab cmdTab;

                cmdTab = iCmdMgr.GetCommandTab(type, Title);

                if (cmdTab == null)
                {
                    cmdTab = (ICommandTab)iCmdMgr.AddCommandTab(type, Title);

                    CommandTabBox cmdBox = cmdTab.AddCommandTabBox();

                    int[] cmdIDs = new int[3];
                    int[] TextType = new int[3];


                    cmdIDs[0] = cmdGroup.get_CommandID(cmdIndex0);
                    System.Diagnostics.Debug.Print(cmdGroup.get_CommandID(cmdIndex0).ToString());
                    TextType[0] = (int)swCommandTabButtonTextDisplay_e.swCommandTabButton_TextHorizontal;

                    cmdIDs[1] = cmdGroup.get_CommandID(cmdIndex1);
                    System.Diagnostics.Debug.Print(cmdGroup.get_CommandID(cmdIndex1).ToString());
                    TextType[1] = (int)swCommandTabButtonTextDisplay_e.swCommandTabButton_TextHorizontal;

                    cmdIDs[2] = cmdGroup.ToolbarId;
                    System.Diagnostics.Debug.Print(cmdIDs[2].ToString());
                    TextType[2] = (int)swCommandTabButtonTextDisplay_e.swCommandTabButton_TextHorizontal | (int)swCommandTabButtonFlyoutStyle_e.swCommandTabButton_ActionFlyout;

                    bResult = cmdBox.AddCommands(cmdIDs, TextType);



                    CommandTabBox cmdBox1 = cmdTab.AddCommandTabBox();
                    cmdIDs = new int[1];
                    TextType = new int[1];

                    cmdIDs[0] = cmdGroup.ToolbarId;
                    TextType[0] = (int)swCommandTabButtonTextDisplay_e.swCommandTabButton_TextBelow | (int)swCommandTabButtonFlyoutStyle_e.swCommandTabButton_ActionFlyout;

                    bResult = cmdBox1.AddCommands(cmdIDs, TextType);

                    cmdTab.AddSeparator(cmdBox1, cmdGroup.ToolbarId);

                }

            }
            thisAssembly = null;
            iBmp.Dispose();
        }

        public int canImport()
        {
            List<Feature> Flist = ( List<Feature>)Properties.Settings.Default.ListofFeatures;
            if (Flist.Count > 0 )
            {
                return 1;
            }
            else
            {
                return 0;
            }

        }

   

        [PreEmptive.Attributes.Feature("ImportPart")]
        public void ImportPart()
        {

            Feature swfeat;
            ModelDoc2 model;

            model = (ModelDoc2)iSwApp.ActiveDoc;
            List<Feature> Flist = (List<Feature>)Properties.Settings.Default.ListofFeatures;
            Properties.Settings.Default.ListofFeatures = Flist;
            swfeat = (Feature)model.FirstFeature();
            for (int ii = 0; ii < Flist.Count; ii += 1)
            {
                //  ListofFeatures[ii].Select(true);
                VersionHistoryID=Flist[ii].GetCreatedVersion();
                SWVersionInfo createdversion = SWVList.Find(
                delegate(SWVersionInfo swver)
                {
                    return swver.VersionHistoryValue == VersionHistoryID;
                }
                );
                 VersionHistoryID=Flist[ii].GetModifiedVersion();
                 SWVersionInfo modifidyversion = SWVList.Find(
                 delegate(SWVersionInfo swver)
                 {
                     return swver.VersionHistoryValue == VersionHistoryID;
                 }
                 );



                 SwApp.SendMsgToUser(string.Format("{0}:{1} created in {2} Modified in {3}", Flist[ii].GetTypeName(), Flist[ii].Name, createdversion.MajorSolidWorksVersion, modifidyversion.MajorSolidWorksVersion));
                //   swfeat =(Feature) swfeat.GetNextFeature();


            }
     

        }
        [PreEmptive.Attributes.Feature("ExportPart")]
        public void ExportPart()
        {
            ModelDoc2 model;
            FeatureManager featMan;
            Feature swfeat;

            
            model = (ModelDoc2)iSwApp.ActiveDoc;
            featMan = model.FeatureManager;

            List<Feature> Flist=new List<Feature>();


            swfeat = (Feature)model.FirstFeature();
            while (swfeat != null)
            {
                Flist.Add(swfeat);
                swfeat = (Feature)swfeat.GetNextFeature();
            }
            Properties.Settings.Default.ListofFeatures = Flist;

           
        }

        public void RemoveCommandMgr()
        {
            iCmdMgr.RemoveCommandGroup(1);
        }

      

        #endregion

    

        #region Event Methods
        public bool AttachEventHandlers()
        {
            AttachSwEvents();
            //Listen for events on all currently open docs
            AttachEventsToAllDocuments();
            return true;
        }

        private bool AttachSwEvents()
        {
            try
            {
                SwEventPtr.ActiveDocChangeNotify += new DSldWorksEvents_ActiveDocChangeNotifyEventHandler(OnDocChange);
                SwEventPtr.DocumentLoadNotify2 += new DSldWorksEvents_DocumentLoadNotify2EventHandler(OnDocLoad);
                SwEventPtr.FileNewNotify2 += new DSldWorksEvents_FileNewNotify2EventHandler(OnFileNew);
                SwEventPtr.ActiveModelDocChangeNotify += new DSldWorksEvents_ActiveModelDocChangeNotifyEventHandler(OnModelChange);
                SwEventPtr.FileOpenPostNotify += new DSldWorksEvents_FileOpenPostNotifyEventHandler(FileOpenPostNotify);
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }



        private bool DetachSwEvents()
        {
            try
            {
                SwEventPtr.ActiveDocChangeNotify -= new DSldWorksEvents_ActiveDocChangeNotifyEventHandler(OnDocChange);
                SwEventPtr.DocumentLoadNotify2 -= new DSldWorksEvents_DocumentLoadNotify2EventHandler(OnDocLoad);
                SwEventPtr.FileNewNotify2 -= new DSldWorksEvents_FileNewNotify2EventHandler(OnFileNew);
                SwEventPtr.ActiveModelDocChangeNotify -= new DSldWorksEvents_ActiveModelDocChangeNotifyEventHandler(OnModelChange);
                SwEventPtr.FileOpenPostNotify -= new DSldWorksEvents_FileOpenPostNotifyEventHandler(FileOpenPostNotify);
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }

        }

        public void AttachEventsToAllDocuments()
        {
            ModelDoc2 modDoc = (ModelDoc2)iSwApp.GetFirstDocument();
            while (modDoc != null)
            {
                if (!openDocs.Contains(modDoc))
                {
                    AttachModelDocEventHandler(modDoc);
                }
                modDoc = (ModelDoc2)modDoc.GetNext();
            }
        }

        public bool AttachModelDocEventHandler(ModelDoc2 modDoc)
        {
            if (modDoc == null)
                return false;

            DocumentEventHandler docHandler = null;

            if (!openDocs.Contains(modDoc))
            {
                switch (modDoc.GetType())
                {
                    case (int)swDocumentTypes_e.swDocPART:
                        {
                            docHandler = new PartEventHandler(modDoc, this);
                            break;
                        }
                    case (int)swDocumentTypes_e.swDocASSEMBLY:
                        {
                            docHandler = new AssemblyEventHandler(modDoc, this);
                            break;
                        }
                    case (int)swDocumentTypes_e.swDocDRAWING:
                        {
                            docHandler = new DrawingEventHandler(modDoc, this);
                            break;
                        }
                    default:
                        {
                            return false; //Unsupported document type
                        }
                }
                docHandler.AttachEventHandlers();
                openDocs.Add(modDoc, docHandler);
            }
            return true;
        }

        public bool DetachModelEventHandler(ModelDoc2 modDoc)
        {
            DocumentEventHandler docHandler;
            docHandler = (DocumentEventHandler)openDocs[modDoc];
            openDocs.Remove(modDoc);
            modDoc = null;
            docHandler = null;
            return true;
        }

        public bool DetachEventHandlers()
        {
            DetachSwEvents();

            //Close events on all currently open docs
            DocumentEventHandler docHandler;
            int numKeys = openDocs.Count;
            object[] keys = new Object[numKeys];

            //Remove all document event handlers
            openDocs.Keys.CopyTo(keys, 0);
            foreach (ModelDoc2 key in keys)
            {
                docHandler = (DocumentEventHandler)openDocs[key];
                docHandler.DetachEventHandlers(); //This also removes the pair from the hash
                docHandler = null;
            }
            return true;
        }
        #endregion

        #region Event Handlers
        //Events
        public int OnDocChange()
        {
            return 0;
        }

        public int OnDocLoad(string docTitle, string docPath)
        {
            return 0;
        }

        int FileOpenPostNotify(string FileName)
        {
            AttachEventsToAllDocuments();
            return 0;
        }

        public int OnFileNew(object newDoc, int docType, string templateName)
        {
            AttachEventsToAllDocuments();
            return 0;
        }

        public int OnModelChange()
        {
            return 0;
        }

        #endregion
    }

}
